(ns
  com.marzhillstudios.molehill.config
  (:use [clojure.contrib.set :only [subset?]]
     [clojure.contrib.with-ns]
     [com.marzhillstudios.molehill.log-util]))

(def *site-config* nil)

(def required-tspec-keys (set '(:index :feed :entry)))

(defn valid-tspec?
  [map]
  {:tag Boolean}
  (let [key-list (keys map)]
    (and (subset? required-tspec-keys (set key-list)))))

(def required-keys (set '(:site-name :site-base-url :site-template-dir :site-root :site-content-dir)))

(defstruct molehill-config :site-name :site-base-url :site-template-dir :site-root :site-index-dir :site-content-dir)

(defn new-config
  "Creates a new config for a molehill site."
  [lst]
  (apply struct-map molehill-config lst))

(defn valid-conf?
  "Validates that the map is a valid config."
  [map]
  {:tag Boolean}
  (let [key-list (keys map)]
    (and (subset? required-keys (set key-list)))))

;assert required values are there
(defmacro defsite
  [site-name & keyvals]
  (let [map (apply struct-map molehill-config keyvals)]
    (assert (valid-conf? map))
    (assert (valid-tspec? map))
    `(do
       (alter-var-root #'*site-config*  (fn [_#] ~map))
       (def ~site-name *site-config*))))

(defmacro with-config
  [fn-name args & body]
  (let [arguments (vec (drop 1 args))]
    `(defn ~fn-name
       (~arguments
          (cond
            (nil? *site-config*)
              (do
                (load-file "sitedef.clj")
                (debug-fmt "config is: %s" (set *site-config*))))
          (~fn-name *site-config* ~@arguments))
       (~args
          ~@body))))

(with-ns 'clojure.core (use ['com.marzhillstudios.molehill.config :only ['defsite]]))
